#include <vfs.h>

#include "minesweeper.h"

#include <input-event-codes.h>
#include <wm.h>
#include <gato/surface.h>
#include <gato/render.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <types.h>

#define BOX_SIZE 20

const char boom1[] = "M394.039216 236.92549C176.188235 236.92549 0.501961 413.615686 0.501961 630.462745 0.501961 848.313725 177.192157 1024 394.039216 1024c217.85098 0 393.537255-176.690196 393.537255-393.537255 1.003922-216.847059-175.686275-393.537255-393.537255-393.537255zM311.717647 409.6c-56.219608 0-145.568627 97.380392-145.568627 177.694118 0 16.062745-13.05098 28.109804-28.109804 28.109804s-28.109804-13.05098-28.109804-28.109804c0-107.419608 110.431373-234.917647 202.792157-234.917647 16.062745 0 28.109804 13.05098 28.109804 28.109804s-13.05098 29.113725-29.113726 29.113725z";
const char boom2[] = "M689.192157 426.666667l-97.380392-97.380392a33.330196 33.330196 0 0 1 0-47.184314L632.972549 240.941176c13.05098-13.05098 34.133333-13.05098 47.184314 0l97.380392 97.380393c13.05098 13.05098 13.05098 34.133333 0 47.184313l-41.160784 41.160785a33.330196 33.330196 0 0 1-47.184314 0z";
const char boom3[] = "M701.239216 317.239216c-9.035294-9.035294-9.035294-25.098039 0-34.133334l131.513725-131.513725c9.035294-9.035294 25.098039-9.035294 34.133334 0 9.035294 9.035294 9.035294 25.098039 0 34.133333L735.372549 317.239216c-9.035294 9.035294-25.098039 9.035294-34.133333 0zM822.713725 117.458824l-46.180392-50.196079c-7.027451-8.031373-7.027451-20.078431 1.003922-27.105882 8.031373-7.027451 20.078431-7.027451 27.105882 1.003921l46.180392 50.196079c7.027451 8.031373 7.027451 20.078431-1.003921 27.105882-7.027451 7.027451-19.07451 6.023529-27.105883-1.003921zM932.141176 161.631373l48.188236 48.188235c7.027451 7.027451 7.027451 20.078431 0 27.105882-7.027451 7.027451-20.078431 7.027451-27.105883 0l-48.188235-48.188235c-7.027451-7.027451-7.027451-20.078431 0-27.105882 8.031373-7.027451 20.078431-7.027451 27.105882 0zM955.231373 40.156863l-50.196079 46.180392c-8.031373 7.027451-8.031373 19.07451-1.003921 27.105882s19.07451 8.031373 27.105882 1.003922l50.196078-46.180392c8.031373-7.027451 8.031373-19.07451 1.003922-27.105883-8.031373-8.031373-20.078431-8.031373-27.105882-1.003921zM858.854902 19.07451l-1.003922 67.262745c0 11.043137 8.031373 19.07451 19.07451 20.078431 11.043137 0 19.07451-8.031373 20.078432-19.07451l1.003921-67.262745c0-11.043137-8.031373-19.07451-19.07451-20.078431-11.043137 0-19.07451 8.031373-20.078431 19.07451zM1003.419608 115.45098l-67.262745 2.007844c-11.043137 0-19.07451 9.035294-19.07451 20.078431s9.035294 19.07451 20.078431 19.07451l67.262745-2.007843c11.043137 0 19.07451-9.035294 19.07451-20.078432-1.003922-11.043137-10.039216-19.07451-20.078431-19.07451z";
const char flag[] = "M288 556.256V223.712l430.464 0.32-120.352 165.952 120.384 166.016L288 556.256z m500.352-12.928l-111.168-153.344 111.168-153.344c12.192-16.832 14.528-35.648 6.368-51.584-8.128-15.936-24.736-25.056-45.568-25.056H288.064A63.968 63.968 0 0 0 224 223.712V864a32 32 0 0 0 64 0v-244H749.152c20.96 0 37.664-9.12 45.76-25.024 8.096-15.872 5.728-34.72-6.56-51.648z";

static void draw_tile(surface_t *base, int x, int y, struct minesweeper_tile *tile)
{
    if (tile->is_opened)
    {
        draw_rectangle(
            base,
            BOX_SIZE * x, BOX_SIZE * y, BOX_SIZE, BOX_SIZE, 0,
            (style_t){
                .fill_color = (x + y) % 2 ? ARGB(0xFFE5C29F) : ARGB(0xFFD7B899),
            });

        if (tile->has_mine)
        {
            draw_svg(base, boom1, 1024, 1024, BOX_SIZE, BOX_SIZE, BOX_SIZE * x, BOX_SIZE * y, ARGB(0xFF000000));
            draw_svg(base, boom2, 1024, 1024, BOX_SIZE, BOX_SIZE, BOX_SIZE * x, BOX_SIZE * y, ARGB(0xFF000000));
            draw_svg(base, boom3, 1024, 1024, BOX_SIZE, BOX_SIZE, BOX_SIZE * x, BOX_SIZE * y, ARGB(0xFFFF0000));
        }
        else if (tile->adjacent_mine_count)
        {
            char s[2] = {'0' + tile->adjacent_mine_count, '\0'};
            draw_text(base, BOX_SIZE * x + 5, BOX_SIZE * y + 2, s, 1, RGB(0x1976D2));
        }
    }
    else
    {
        if (tile->has_flag)
        {
            draw_svg(base, flag, 1024, 1024, BOX_SIZE, BOX_SIZE, BOX_SIZE * x, BOX_SIZE * y, ARGB(0xFFFF0000));
        }
        else
        {
            draw_rectangle(
                base,
                BOX_SIZE * x, BOX_SIZE * y, BOX_SIZE + 0.5, BOX_SIZE, 0,
                (style_t){
                    .fill_color = (x + y) % 2 ? ARGB(0xFFAAD751) : ARGB(0xFFA2D149),
                });
        }
    }
}

unsigned W = 10;
unsigned H = 10;

void tile_updated(struct minesweeper_game *game, window_t *win)
{
    for (int y = 0; y < H; y++)
    {
        for (int x = 0; x < W; x++)
        {
            struct minesweeper_tile *tile = minesweeper_get_tile_at(game, x, y);

            draw_tile(win->connect.surface, x, y, tile);
        }
    }
    wm_window_update(win);
}

void game_mine_sweeper(window_t *win)
{
    unsigned W = 10;
    unsigned H = 10;
    uint8_t *game_buffer = malloc(minesweeper_minimum_buffer_size(W, H));
    struct minesweeper_game *game = minesweeper_init(W, H, 0.1, game_buffer);
    tile_updated(game, win);

    for (;;)
    {
        while (1)
        {
            wm_event_t e;
            wm_window_poll_event(win, &e, NULL);

            if (WM_MOUSEBUTTONDOWN_EVENT == e.type)
            {
                int x = e.mouse_buttondown_event.x / BOX_SIZE;
                int y = e.mouse_buttondown_event.y / BOX_SIZE;
                struct minesweeper_tile *tile = minesweeper_get_tile_at(game, x, y);

                if (e.mouse_buttondown_event.code == BTN_LEFT)
                {
                    minesweeper_open_tile(game, tile);
                    if (tile->has_mine)
                    {
                        tile_updated(game, win);
                        draw_text(win->connect.surface, 20, 200 / 2 - 32, "Game Over", 2, RGB(0xff0000));
                        wm_window_update(win);
                        return;
                    }
                }
                else
                {
                    minesweeper_toggle_flag(game, tile);
                }
                tile_updated(game, win);
                break;
            }
        }
    }
}

int main(int argc, char **argv)
{
    do_wm_init();
    window_t *win = wm_window_create(200, 150, 200, 200, RGB(0xffffff));
    wm_window_event_mask_set(win, WM_ABS_EVENT | WM_MOUSEBUTTONDOWN_EVENT);
    wm_window_show(win);
    game_mine_sweeper(win);
    return 0;
}